package com.opentd.files;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.net.URL;
import java.util.Vector;

import com.opentd.game.Game;
import com.opentd.game.maps.Map;
import com.opentd.graphics.Block;
import com.opentd.graphics.Level;
import com.opentd.npc.Wave;

public class LevelManager {
	
	public class LevelReader {
		String title = "Unnamed Level - Open Tower Defense";
		boolean inWaves = false, inLayout = false;
		boolean autoGenWaves;
		boolean boss;
		boolean firstTimeInWaves = true;
		int health = 100;
		int money = 50;
		int enemyHealth = -1, numberOfEnemies = -1, enemyID = -1;
		int numWaves;
		int wavesFound;
		Vector<Wave> waves;
		int width, height;
		int y = 0;
		Map map;
		
		public Level readLevel(File file){
			try{
				if(!file.canRead()){
					System.out.println("Cannot read file" + file.getAbsolutePath());
				}
				
				BufferedReader in = new BufferedReader(new FileReader(file));
				String line = null;
				while((line = in.readLine()) != null){
					//System.out.println("Processing line: " + line + " -- ");
					process(line);
				}
				try{
					in.close();
				}catch(Exception e){
					
				}
				
				//Generate waves if the file says to.
				if(autoGenWaves){
					//System.out.println("Generating waves");
					waves = new Vector<Wave>();
					for(int i = 0; i < numWaves; i++){
						int num = i + 1;
						int health = i + enemyHealth;
						waves.add(new Wave(num, health, 1));
						if(boss){
							if(i == numWaves){
								waves.add(new Wave(1, 1000, 2));
							}
						}
					}
				}
				
				Level l = new Level(title, health, money, waves, map);
				
				return l;
			}catch(IOException e){
				e.printStackTrace();
				return null;
			}
		}
		
		private void process(String line){
			if(line.startsWith("//") || line.startsWith("<<"))
				return;
			if(inWaves){
				//check for the end of the waves tag
				if(line.contains("[/WAVES]")){
					inWaves = false;
					return;
				}
				if(autoGenWaves){
					//System.out.println("In waves, but auto gen waves is true. Returning");
					return;
				}
				if(firstTimeInWaves){
					waves = new Vector<Wave>();
					firstTimeInWaves = false;
				}
				//Check if the line defines a new wave
				if(line.contains("WAVE:")){
					wavesFound++;
					enemyHealth = -1;
					numberOfEnemies = -1;
					enemyID = -1;
					String[] params = line.split(" ");
					for(String param : params){
						//System.out.println("+++ PARAM: " + param);
						if(param.contains("health")){
							enemyHealth = extractEnemyHealth(param);
							//System.out.println("enemyHealth = " + enemyHealth);
						}
						if(param.contains("amount")){
							numberOfEnemies = extractEnemies(param);
							//System.out.println("numberOfEnemies = " + numberOfEnemies);
						}
						if(param.contains("id")){
							enemyID = extractID(param);
							//System.out.println("enemyID = " + enemyID);
						}
					}
					if(enemyHealth < 0)
						enemyHealth = 10;
					if(numberOfEnemies < 0)
						numberOfEnemies = 1;
					if(enemyID < 0)
						enemyID = 1;
					waves.add(new Wave(numberOfEnemies, enemyHealth, enemyID));
					//System.out.println("Wave added: number of enemies = " + numberOfEnemies + " enemy health = " + enemyHealth + " enemID = " + enemyID);
				}
			}else if(inLayout){
				//check for the end of the layout tag.
				if(line.contains("[/LAYOUT]")){
					inLayout = false;
					return;
				}
				String [] row = line.replace("	", "").split(" ");
				for(int i = 0; i < row.length; i ++){
					if(row[i].contains("+")){
						map.addSpawnBlock(Game.Block.PATH_BLOCK_ID, i, y);
						continue;
					}else if(row[i].contains("-")){
						map.addFinishBlock(Game.Block.FINISH_BLOCK_ID, i, y);
						continue;
					}else{
						int blockType = Integer.parseInt(row[i]);
						map.addBlock(blockType, i, y);
					}
				}
				y++;
			}else{
				//Check for title
				if(line.contains("TITLE:")){
					line = line.replace("TITLE:", "");
					//System.out.println(line);
					title = line;
					return;
				}
				//Check for health
				if(line.contains("HEALTH:")){
					line = line.replace("HEALTH:", "");
					line = line.replace(" ", "");
					health = Integer.parseInt(line);
					return;
				}
				//Check for money
				if(line.contains("MONEY:")){
					line = line.replace("MONEY:", "");
					line = line.replace(" ", "");
					money = Integer.parseInt(line);
					return;
				}
				//check for the beginning of the [waves] tag
				if(line.contains("[WAVES")){
					String[] params = line.split(" ");
					for(String param : params){
						//System.out.println("+++ PARAM: " + param);
						if(param.contains("count="))
							numWaves = extractWaves(param);
						if(param.contains("auto="))
							autoGenWaves = extractAutoGenWaves(param);
						if(param.contains("boss="))
							boss = extractBoss(line);
						if(param.contains("start_health="))
							enemyHealth = extractHealth(param);
					}
					inWaves = true;
				}
				//check for the beginning of the layout tag
				if(line.contains("[LAYOUT")){
					//System.out.println("Layout tag found");
					String[] params = line.split(" ");
					for(String param : params){
						//System.out.println("+++ PARAM: " + param);
						if(param.contains("width="))
							width = extractWidth(param);
						if(param.contains("height="))
							height = extractHeight(param);
					}
					//System.out.println("width: " + width);
					//System.out.println("height: " + height);
					map = new Map(width, height);
					inLayout = true;
				}
			}
			
		}
		
		private int extractWaves(String line){
			line = line.replace("count=", "");
			line = line.replace(" ", "");
			line = line.replace("]", "");
			return Integer.parseInt(line);
		}
		
		private int extractHealth(String line){
			line = line.replace("start_health=", "");
			line = line.replace(" ", "");
			line = line.replace("]", "");
			return Integer.parseInt(line);
		}
		
		private int extractEnemyHealth(String line){
			line = line.replace("health=", "");
			line = line.replace(" ", "");
			line = line.replace("]", "");
			return Integer.parseInt(line);
		}
		
		private int extractEnemies(String line){
			line = line.replace("amount=", "");
			line = line.replace(" ", "");
			line = line.replace("]", "");
			return Integer.parseInt(line);
		}
		
		private int extractID(String line){
			line = line.replace("id=", "");
			line = line.replace(" ", "");
			line = line.replace("]", "");
			return Integer.parseInt(line);
		}
		
		private int extractWidth(String line){
			line = line.replace("width=", "");
			line = line.replace(" ", "");
			line = line.replace("]", "");
			return Integer.parseInt(line);
		}
		
		private int extractHeight(String line){
			line = line.replace("height=", "");
			line = line.replace(" ", "");
			line = line.replace("]", "");
			return Integer.parseInt(line);
		}
		
		private boolean extractAutoGenWaves(String line){
			line = line.replace("auto=", "");
			line = line.replace(" ", "");
			line = line.replace("]", "");
			return Boolean.parseBoolean(line);
		}
		
		private boolean extractBoss(String line){
			line = line.replace("boss=", "");
			line = line.replace(" ", "");
			line = line.replace("]", "");
			return Boolean.parseBoolean(line);
		}
	}
	
	public static void loadLevels(String path){
		File mapDir = new File(path);
		String[] filePaths = mapDir.list();
		
		for(String filePath : filePaths){
			File f = new File(path + "/" + filePath);
			if(!validate(f)){
				System.out.println("About to process file: " + filePath);
			}				
			Game.levels.add(new LevelManager().new LevelReader().readLevel(f));
		}
		
	}
	
	public static boolean validate(File file){
		if(!file.canRead()){
			return false;
		}
		return true;
	}
}
